﻿using FanaticRock.AudioManage.Models;
using FanaticRock.Core.AudioPlay.Events;
using FanaticRock.Core.DI;
using FanaticRock.Core.Enums;
using FanaticRock.Core.Extensions;
using FanaticRock.Core.Helpers;
using FanaticRock.Core.Interfaces;
using FanaticRock.Core.Models;
using FanaticRock.Core.ServiceInterfaces;
using System.Collections.Frozen;

namespace FanaticRock.AudioManage.Services
{
    [InjectMe(typeof(IPlayListService))]
    public class PlayListService : IPlayListService, ILogger
    {
        #region dependency

        private ISongProviderService _songProviderService;

        private IAudioPlayService _audioPlayService;

        private ILocalDbService _localDbService;

        #endregion

        #region events

        public event EventHandler<PlayListChangedEventArgs> PlayListChanged;

        public event EventHandler<AudioPlayedEventArgs> AudioPlayed;

        #endregion

        #region fields

        ///<summary>播放列表。</summary>
        public IReadOnlyList<Song> PlayList => _playList;
        private List<SongInPlayList> _playList = new List<SongInPlayList>();

        private SongInPlayList _currentSong;

        ///<summary>当前的播放模式，如单曲循环，列表循环，随机等</summary>
        public PlayModeEnum PlayModeEnum => _playModeEnum;
        private PlayModeEnum _playModeEnum = PlayModeEnum.ListLoop;

        #endregion

        #region ctors

        public PlayListService(ISongProviderService songProviderServide,
                               IAudioPlayService audioPlayService,
                               ILocalDbService localDbService)
        {
            _songProviderService = songProviderServide;
            _audioPlayService = audioPlayService;
            _localDbService = localDbService;

            var songs = songProviderServide.GetSongs();
            var songsInList = songs.Select(s => new SongInPlayList(s)).ToList();

            // 更新列表。
            _playList.AddRange(songsInList);
            CollectionHelper.UpdateIndex(songsInList, (i, Index) => i.PlayIndex = Index);

            audioPlayService.MediaPlayEnd += AudioPlayService_MediaPlayEnd;
        }



        #endregion

        #region event callback

        private void AudioPlayService_MediaPlayEnd(object? sender, EventArgs e)
        {
            switch (_playModeEnum)
            {
                case PlayModeEnum.ListLoop:
                    PlayNext();
                    break;
                case PlayModeEnum.SingleLoop:
                    Replay();
                    break;
                case PlayModeEnum.Random:
                    PlayNext();
                    break;
                case PlayModeEnum.OneByOne:
                    PlayNext();
                    break;
                case PlayModeEnum.Heart:
                    PlayNext();
                    break;
                default:
                    break;
            }
        }

        #endregion

        #region methods

        public async Task SetPlayList(IEnumerable<Song> newList)
        {
            if (newList == null) { this.Info($"PlayListService.SetPlayList: newList 为空"); return; }

            Clear();

            if (newList.Count() == 0) return;

            var songsInList = newList.Select(s => new SongInPlayList(s));
            _playList.AddRange(songsInList);
            CollectionHelper.UpdateIndex(_playList, (i, index) => i.PlayIndex = index);

            var addArgs = PlayListChangedEventArgs.CreateFromAdd(newList);
            PlayListChanged?.Invoke(this, addArgs);
        }

        public async Task Clear()
        {
            _playList.Clear();

            var refreshArgs = PlayListChangedEventArgs.CreateFromReset();
            PlayListChanged?.Invoke(this, refreshArgs);
        }

        public async Task<Song> GetSongById(string id)
        {
            return await GetSongByIdCore(id);
        }

        private async Task<SongInPlayList> GetSongByIdCore(string id)
        {
            var song = _playList.FirstOrDefault(i => string.Equals(i.Id, id));
            return song;
        }

        public async Task Remove(string id)
        {
            var song = await GetSongByIdCore(id);
            if (song == null) return;
            _playList.Remove(song);

            var addArgs = PlayListChangedEventArgs.CreateFromDelete([song]);
            PlayListChanged?.Invoke(this, addArgs);
        }

        public async Task AddSong(Song song)
        {
            if (song == null) { this.Info($"PlayListService.AddSong: 对于新传入的 song {song} 已经存在 currentSong 为 null"); return; }
            var currentSong = await GetSongById(song.Id);
            if (currentSong != null) { this.Info($"PlayListService.AddSong: 对于新传入的 song {song} 已经存在 currentSong {currentSong}"); return; }

            var songInList = new SongInPlayList(song);

            _playList.Add(songInList);

            CollectionHelper.UpdateIndex(_playList, (i, index) => i.PlayIndex = index);


            var addArgs = PlayListChangedEventArgs.CreateFromAdd([song]);
            PlayListChanged?.Invoke(this, addArgs);
        }

        public async Task AddSongRange(IEnumerable<Song> songs)
        {
            // 建立 Id 映射。
            var songTempDictionary = _playList.ToFrozenDictionary(s => s.Id);
            var existsList = new List<SongInPlayList>();
            foreach (var song in songs)
            {
                var songId = song.Id;
                if (songTempDictionary.TryGetValue(songId, out var existSong))
                {
                    existsList.Add(existSong);
                }
            }

            foreach (var existSong in existsList)
            {
                _playList.Remove(existSong);
            }

            if (existsList.Count != 0)
            {
                var addArgs = PlayListChangedEventArgs.CreateFromDelete(existsList);
                PlayListChanged?.Invoke(this, addArgs);
            }

            if (songs.Count() != 0)
            {
                var songsInList = songs.Select(s => new SongInPlayList(s));
                _playList.AddRange(songsInList);

                var addArgs = PlayListChangedEventArgs.CreateFromAdd(songs);
                PlayListChanged?.Invoke(this, addArgs);
            }

            CollectionHelper.UpdateIndex(_playList, (i, index) => i.PlayIndex = index);

        }

        public async Task Play(string id)
        {
            var song = await GetSongByIdCore(id);
            Play(song);
        }

        public async Task Play(Song song)
        {
            if (song == null)
            {
                this.Info($"PlayListService.Play: 对于新传入的 song {song} 已经存在 currentSong 为 null");
                return;
            }

            if (song is SongInPlayList songInList)
            {
                await PlayCore(songInList);
            }
            else
            {
                var songInListFromSong = await GetSongByIdCore(song.Id);
                await PlayCore(songInListFromSong);
            }
        }

        public async Task PlayCore(SongInPlayList song)
        {
            if (song == null)
            {
                this.Info($"PlayListService.Play: 对于新传入的 song {song} 已经存在 currentSong 为 null");
                return;
            }

            var uri = song.Uri;
            _currentSong = song;
            await _audioPlayService.Open(uri);
            await _audioPlayService.Play();
            AudioPlayed?.Invoke(this, new AudioPlayedEventArgs() { Song = song });
        }

        public async Task Play()
        {
            if (_currentSong == null)
            {
                var newSong = _playList.FirstOrDefault();
                await Play(newSong);
            }
            else
            {
                _audioPlayService.Play();
            }
        }

        public async Task Pause()
        {
            await _audioPlayService?.Pause();
        }

        public async Task SetPlayModeEnum(PlayModeEnum playModeEnum)
        {
            _playModeEnum = playModeEnum;

            switch (playModeEnum)
            {
                case PlayModeEnum.Random:
                    var random = new Random();
                    var playArray = _playList.ToArray();
                    random.Shuffle(playArray);
                    SetPlayList(playArray);
                    break;
                default:
                    break;
            }
        }

        public async Task PlayNext()
        {
            if (_currentSong == null) _playList.FirstOrDefault();
            var index = _playList.IndexOf(_currentSong);
            if (index == -1) return;
            if (index >= _playList.Count - 1) return;
            var newIndex = index + 1;
            var newSong = _playList[newIndex];
            Play(newSong);
        }

        public async Task PlayPreview()
        {
            if (_currentSong == null) _playList.FirstOrDefault();
            var index = _playList.IndexOf(_currentSong);
            if (index == -1) return;
            if (index <= 0) return;
            var newIndex = index - 1;
            var newSong = _playList[newIndex];
            Play(newSong);
        }

        public async Task Replay()
        {

        }

        ///<summary>保存列表。</summary>
        public async Task SaveList(bool forced)
        {
            if(forced == false)
            {
                if (_localDbService.IsChanged() == false) return;
            }
   
            await _localDbService.Clear<SongInPlayList>();
            await _localDbService.UpsertAsync<SongInPlayList>(_playList);
        }

        #endregion


    }
}
